<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <title>サブルーチンをシミュレートするクロージャ</title>
  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
  <script src="./lib/prototype.js" type="text/javascript"></script>
  <script src="./lib/scriptaculous.js" type="text/javascript"></script>
  <script type="text/javascript" src="./yahoo/yahoodomevent/yahoodomevent.js"></script>
  <script type="text/javascript" src="./yahoo/history/historybetamin.js"></script>
  <link rel="stylesheet" type="text/css" href="./yahoo/colorpicker/assets/skins/sam/colorpicker.css" />
  <script type="text/javascript" src="./yahoo/utilities/utilities.js"></script>
  <script type="text/javascript" src="./yahoo/slider/slidermin.js"></script>
  <script type="text/javascript" src="./yahoo/colorpicker/colorpickerbetamin.js"></script>
  <style type="text/css">
  /*margin and padding on body element
    can introduce errors in determining
    element position and are not recommended;
    we turn them off as a foundation for YUI
    CSS treatments. */
  body {
	margin:0;
	padding:0;
  }
  #container { position: relative; padding: 6px; background-color: #eeeeee; width: 420px; height:220px; }
  </style>
  <script type="text/javascript" language="javascript">
  // <![CDATA[
'a big blockquote br b center code div em form h1 h2 h3 h4 h5 h6 hr img iframe input i li ol option pre p script select small span strong style sub sup table tbody td textarea th tr ul u'.split(' ').each(function(e) {
  window['$' + e] = function() {
    if (arguments[0]) {
      if (arguments[0].nodeType) return Builder.node(e,$A(arguments));
      if (arguments[1]) return Builder.node(e,arguments[0],$A(arguments).slice(1));
      return Builder.node(e,arguments[0]);
    };
    return Builder.node(e);
  };
});

var cont_table = [];
var q_table = [];

// show :: Element -> IO ()
function show(el){
  //remove all children from <div id="main">.
  var e = $('main');
  while (e.firstChild) e.removeChild(e.firstChild);
  e.appendChild(el);
}

// action :: (unit -> Hash) -> (Hash -> IO ()) -> String
function action(func_q,thunk) {  
  var kurl = cont_table.push(thunk) - 1;  
  q_table[kurl] = func_q;
  return 'navi(' + kurl + ')';
}

// navi :: Number -> IO ()
function navi(kurl) {
 YAHOO.util.History.navigate('kurl',String(kurl));
}

// do_action :: Number -> IO ()
function do_action(kurl) {
  if (typeof q_table[kurl] === 'function')
    q_table[kurl] = q_table[kurl].call();
  var thunk = cont_table[kurl];
  thunk(q_table[kurl]);
}

function colorpicker_setup() {
  var Event = YAHOO.util.Event, picker;
  Event.onDOMReady(function() {
		     YAHOO.log("Creating Color Picker.", "info", "example");
		     picker = new YAHOO.widget.ColorPicker("container", {
                                           		       showhsvcontrols: true,
							       showhexcontrols: true,
							       images: {
							         PICKER_THUMB: "yahoo/colorpicker/assets/picker_thumb.png",
								 HUE_THUMB: "yahoo/colorpicker/assets/hue_thumb.png"
								 }
		       });
		     YAHOO.log("Finished creating Color Picker.", "info", "example");
		     
		     //a listener for logging RGB color changes;
		     //this will only be visible if logger is enabled:
		     var onRgbChange = function(o) {
		       /*o is an object
			 { newValue: (array of R, G, B values),
			 prevValue: (array of R, G, B values),
			 type: "rgbChange"
			 }
		       */
		       YAHOO.log("The new color value is " + o.newValue, "info", "example");
		     }
		     
		     //subscribe to the rgbChange event;
		     picker.on("rgbChange", onRgbChange);
		     
		     //use setValue to reset the value to white:
		     Event.on("reset", "click", function(e) {
				picker.setValue([255, 255, 255], false); //false here means that rgbChange
				//wil fire; true would silence it
			      });
			
		     //use the "get" method to get the current value
		     //of one of the Color Picker's properties; in 
		     //this case, we'll get the hex value and write it
		     //to the log:
		     Event.on("gethex", "click", function(e) {
				var hex = picker.get('hex');
				eval(action(function() {return $H({color: hex})}, main));
			      });
		   });
}

// main :: Hash -> IO ()
function main(query) {
  show($div({style: 'background:#' + query['color'] + ';'},
	    $a({href: 'http://practical-scheme.net/wiliki/wiliki.cgi?%e3%82%a6%e3%82%a7%e3%83%96%e3%83%99%e3%83%bc%e3%82%b9%e3%82%a2%e3%83%97%e3%83%aa%e3%82%b1%e3%83%bc%e3%82%b7%e3%83%a7%e3%83%b3%e3%81%ae%e3%81%9f%e3%82%81%e3%81%aeLisp'}, '引用元 - Wiliki:ウェブベースアプリケーションのためのLisp'),
	    $h1('サブルーチンをシミュレートするクロージャ'),
	    $p('ウェブページをUIとして使用することの問題の1つはウェブセッションが本来ステートレスだということである。私たちは、サブルーチンのような振舞いをシミュレートするのにレキシカルクロージャを使用することによって、これを回避した。あなたがコンティニュエーションを理解しているなら、私たちがしたことについて説明する1つの方法は私たちはコンティニュエーション渡し形式でソフトウェアを書いたということだ。'),
	    $p('ほとんどのウェブベースのソフトウェアは、リンクを生成するとき「ユーザがこのリンクをクリックしたら、このcgiをこの引数で呼び出して欲しい」、と思っている。私たちのソフトウェアがリンクを生成するとき、「ユーザがこのリンクをクリックしたら、このコードを走らせたい」と思うかもしれない。そして、コードの断片はことによると、値が周囲の文脈からきた自由な変項を含む任意のコードである可能性がある（実際はほとんど）。'),
	    $p('私たちがこれを行った方法は、クロージャであると予想される初期値を持ち、コードの本体が続くマクロを書くことだった。そのコードはグローバルなハッシュ表にユニークなIDで格納され、本体のコードから生成されたあらゆる出力はそのハッシュキーを含むURLのリンクになった。そのリンクがクリックされた次のものであるなら、私たちのソフトウェアは、対応するコードの断片を探し呼び出すだろう、そして連鎖は続く。事実上私たちはcgiスクリプトをその場で書いていた、それらが周囲の文脈を示すことができたクロージャであったのを除いて。'),
	    $p('これはとても空論に聞こえるので、このテクニックが明白な違いを作ったという例をあげる。あなたがウェブベースのアプリケーションでしばしばしたいことの1つは様々なタイプのプロパティがあるオブジェクトを編集することだ。オブジェクトのいくつものプロパティはフォームのフィールドやメニューとして表すことができる。例えば人をあらわすオブジェクトを編集しているとして、名前のためにフィールドを取るだろう、タイトルにおいて、特選しているメニュー。'),
	    $p('ここで、あるオブジェクトに色というプロパティがあるとき、どうなるだろうか？下部にある更新ボタンですべてが１つのフォームで起きる、普通のcgiスクリプトを使っていたら、あなたは苦労するだろう。テキストフィールドを使用して、ユーザにrgb番号をタイプさせることもできるが、エンドユーザはそれが好きではない。可能な色のメニューを持つこともできるが、そうすると可能な色を制限しなければならない、そうでなければ単に標準のウェブのカラーマップを提供するためだけに、256個のほとんど区別できない名前のメニュー項目が必要になる。'),
	    $input({type: 'button', value: '変更', onclick: action('', function(query) {
								     show($div($div({id: 'container'}),
									       $input({type: 'button', id: 'reset', value: 'Reset Color to White'}),
									       $input({type: 'button', id: 'gethex', value: 'Pick up Color'})));
								     colorpicker_setup();
								   })}),
	    $p('Viawebでは、「変更」と書かれたボタンによって現在の値を表現する見本として色を見せることができた。ユーザが変更ボタンをクリックすると、選択できる色のイメージマップのページへ飛ぶ。色を選ぶと、オブジェクトの色が変わってプロパティの編集画面に戻ってくる。これが私がサブルーチンのような振舞いをシミュレートする、という意味だ。ソフトウェアはまるで色を選んだところから戻るかのように振舞うことができた。もちろんそうではない；それはスタックを戻るように見える、新しいcgi呼び出しである。しかしクロージャを使うことで、ユーザに、また私たちにも、単にサブルーチンコールをしているように見せることが出来た。私たちは、「ユーザがこのリンクをクリックしたら、色選択ページに行き、そうしたらここに戻って来い」というコードを書くことが出来た。これは単にこの可能性のアドバンテージをとったうちのひとつである。それにより私たちのソフトウェアは私たちの競争相手のものより明らかに洗練されるようになった。')));
}
  // ]]>
  </script>
</head>
<body>
<script>
YAHOO.util.History.register('kurl', '0', function(state) {
  do_action(Number(state));
} );

YAHOO.util.History.onLoadEvent.subscribe(function() {
  cont_table = new Array();
  q_table = new Array();
  action(function() {return $H({color: 'ffffff'})}, main);
  do_action(0);
} );

YAHOO.util.History.initialize();
</script>
<div id="main">Please enable the javascript.</div>
</body>
</html>
